//! 根据struct字段信息，生成select fields信息

//use proc_macro2::TokenStream as TokenStream2;
//use quote::quote;

use super::struct_field_parse::{FieldConvertType, TinyOrmFieldData};
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};

/// select字段和更新字段及更新所有字段token
pub(super) struct TinyOrmFieldSumInfo {
    pub(super) select_fields_sql: String,
    pub(super) update_set_fields_sql: String,
    /// 更新所有和新增insert的代码
    pub(super) update_all_and_insert_token: TokenStream2,
}
/// 解析当前表的select field
///
/// # 返回
/// (select fields部分，update fields部分)
pub(super) fn impl_orm_field(
    orm_field_list: &[TinyOrmFieldData],
    pk_self_fields: &Vec<TokenStream2>,
    join_self_fields: Option<&Vec<TokenStream2>>,
    table_name: &str,
) -> TinyOrmFieldSumInfo {
    let select_fields = orm_field_list
        .iter()
        .map(|field| {
            let field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            format!("{}.{}", table_name, &field.field_db_name)
        })
        .collect::<Vec<_>>()
        .join(", ");

    // 非主键和join字段的update sql
    let update_fields_normal_sql = orm_field_list
        .iter()
        .filter_map(|field| {
            let field = match field {
                TinyOrmFieldData::Normal(field) => field,
                _ => return None,
            };
            Some(format!("{}.{} = ?", table_name, &field.field_db_name))
        })
        .collect::<Vec<_>>()
        .join(", ");
    
    // 非主键和join的self.field
    let normal_self_fields = orm_field_list
        .iter()
        .filter_map(|field| {
            let field = match field {
                TinyOrmFieldData::Normal(field) => field,
                _ => return None,
            };
            let field_ident = field.field_ident.clone();
            Some(match field.field_type_convert_type {
                //FieldConvertType::Option => quote! { self.#field_ident.unwrap() },
                // Option 类型的字段，更新时不自动wrap，如为None则更新为null,避免Option为None时报错
                FieldConvertType::Option | FieldConvertType::String => quote! { &self.#field_ident },
                FieldConvertType::None => quote! { self.#field_ident },
            })
        })
        .collect::<Vec<_>>();
    // 生成insert into的相关sql
    let insert_token = generate_insert_info(orm_field_list, table_name);
    // 生成orm_update方法
    let update_token = generate_update_info(orm_field_list,pk_self_fields,table_name);
    // 生成orm_query_with方法
    let query_token = generate_query_info(orm_field_list,table_name);
    // 生成orm_get_with方法
    let get_token = generate_get_info(orm_field_list,table_name);

    //println!("{:?}",normal_self_fields);
    if let Some(join_self_fields) = join_self_fields {
        // 有join字段
        // join字段的update sql
        let update_fields_join_sql = orm_field_list
            .iter()
            .filter_map(|field| {
                let field = match field {
                    TinyOrmFieldData::Join(join_field) => &join_field.field,
                    _ => return None,
                };
                Some(format!("{}.{} = ?", table_name, &field.field_db_name))
            })
            .collect::<Vec<_>>()
            .join(", ");

        let update_fields_sql = format!("{}, {}", update_fields_normal_sql, update_fields_join_sql);
        // 生成orm_update_all 方法
        let code = quote! {
            /// orm自动实现：根据主键更新当前记录的所有字段
            pub async fn orm_update_all(&self,pool: &TinyOrmDbPool) -> AnyhowResult<()>{
                let sql = Self::DB_META.update_sql;
                let query = Self::db_query(&sql)
                    #(.bind(#normal_self_fields))*
                    #(.bind(#join_self_fields))*
                    #(.bind(#pk_self_fields))*;
                Self::db_execute(pool, query).await
                    .with_context(|| "更新当前所有记录")?;
                Ok(())
            }

            #insert_token

            #update_token

            #query_token

            #get_token
        };

        TinyOrmFieldSumInfo {
            select_fields_sql: select_fields,
            update_set_fields_sql: update_fields_sql,
            update_all_and_insert_token: code,
        }
    } else {
        let update_fields_sql = update_fields_normal_sql;
        // 生成orm_update_all 方法
        let code = quote! {
            /// orm自动实现：根据主键更新当前记录的所有字段
            pub async fn orm_update_all(&self,pool: &TinyOrmDbPool) -> AnyhowResult<()>{
                let sql = Self::DB_META.update_sql;
                let query = Self::db_query(&sql)
                    #(.bind(#normal_self_fields))*
                    #(.bind(#pk_self_fields))*;
                Self::db_execute(pool, query).await
                    .with_context(|| "更新当前所有记录")?;
                Ok(())
            }

            #insert_token

            #update_token

            #query_token

            #get_token
        };

        TinyOrmFieldSumInfo {
            select_fields_sql: select_fields,
            update_set_fields_sql: update_fields_sql,
            update_all_and_insert_token: code,
        }
    }
}

fn generate_insert_info(orm_field_list: &[TinyOrmFieldData], table_name: &str) -> TokenStream2 {
    
    let insert_into_sql = orm_field_list
        .iter()
        .filter_map(|field| {
            
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.auto_pk {
                // 自动递增字段跳过
                None
            } else {
                Some(inner_field.field_db_name.as_str())
            }
        })
        .collect::<Vec<_>>()
        .join(", ");
    let insert_value_tokens_let = orm_field_list
        .iter()
        .enumerate()
        .filter_map(|(index,field)| {
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.auto_pk {
                // 自动递增字段跳过
                None
            } else {
                let field_ident = &inner_field.field_ident;
                let temp_var = format_ident!("var_{index}");
                let token = if let TinyOrmFieldData::Join(join_field) = field {
                    let link_id = format_ident!("{}", join_field.link_id);
                    // 考虑可能需要写入null的场景，不对Option进行unwrap
                    match inner_field.field_type_convert_type {
                        FieldConvertType::Option => quote! { let #temp_var = &self.#field_ident.as_ref().map(|field| &field.#link_id);  },
                        FieldConvertType::String => quote! { let #temp_var = &self.#field_ident.#link_id; },
                        FieldConvertType::None => quote! { let #temp_var = &self.#field_ident.#link_id;  },
                    }
                    /*
                    match inner_field.field_type_convert_type {
                        FieldConvertType::Option => quote! { self.#field_ident.unwrap().#link_id  },
                        FieldConvertType::String => quote! { &self.#field_ident.#link_id  },
                        FieldConvertType::None => quote! { &self.#field_ident.#link_id  },
                    }
                    */
                } else {
                    // 考虑可能需要写入null的场景，不对Option进行unwrap
                    quote! { let #temp_var = &self.#field_ident; }
                    /*
                    match inner_field.field_type_convert_type {
                        FieldConvertType::Option => quote! { self.#field_ident.unwrap() },
                        FieldConvertType::String => quote! { &self.#field_ident },
                        FieldConvertType::None => quote! { &self.#field_ident },
                    } */
                };
                Some(token)
            }
        })
        .collect::<Vec<_>>();
    let insert_value_tokens = orm_field_list
        .iter()
        .enumerate()
        .filter_map(|(index,field)| {
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.auto_pk {
                // 自动递增字段跳过
                None
            } else {
                let temp_var = format_ident!("var_{index}");
                Some(temp_var)
            }
        })
        .collect::<Vec<_>>();
    let auto_pk_token = orm_field_list
        .iter()
        .find_map(|field| {
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.auto_pk {
                // 自动递增字段
                let field_ident = &inner_field.field_ident;
                let field_type = &inner_field.field_type;
                Some(match inner_field.field_type_convert_type {
                    FieldConvertType::Option => {
                        quote! { self.#field_ident = Some(resp.last_insert_id() as #field_type);}
                    }
                    _ => quote! { self.#field_ident = (resp.last_insert_id() as #field_type); },
                })
            } else {
                None
            }
        })
        .unwrap_or_else(|| quote! {});

    let insert_len = insert_value_tokens.len();
    let insert_into_value_sql = vec!["?"; insert_len].join(", ");
    let insert_sql =
        format!("INSERT INTO {table_name} ({insert_into_sql}) VALUES ({insert_into_value_sql})");
    //println!("{insert_sql}");
    let code = quote! {
        /// 在数据库中插入当前记录
        /// 
        /// 用于新增记录的保存
        /// 
        /// # 参数说明
        /// 
        /// * pool 连接池
        pub async fn orm_insert(&mut self, pool: &TinyOrmDbPool) -> AnyhowResult<()> {
            let sql = #insert_sql;
            
            #(
                #insert_value_tokens_let
            )*

            let query = Self::db_query(&sql)
                #(.bind(#insert_value_tokens))*;
            let resp = Self::db_execute(pool, query)
                .await
                .with_context(|| "插入数据表记录错误")?;
            #auto_pk_token
            Ok(())
        }
    };

    code
}

/// 生成字段的orm_update方法
fn generate_update_info(orm_field_list: &[TinyOrmFieldData],pk_self_fields: &Vec<TokenStream2>,table_name:&str) -> TokenStream2 {    
    let update_tokens = orm_field_list
        .iter()
        .filter_map(|field| {
            
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.is_orm_update {
                // 生成该字段的orm_update方法
                let fn_name = format_ident!("orm_update_{}",inner_field.field_ident);
                let field_ident = &inner_field.field_ident;
                let value_token = if let TinyOrmFieldData::Join(join_field) = field {
                    let link_id = format_ident!("{}", join_field.link_id);
                    // 考虑可能需要写入null的场景，不对Option进行unwrap
                    match inner_field.field_type_convert_type {
                        FieldConvertType::Option => quote! { self.#field_ident.map(|field| field.#link_id)  },
                        FieldConvertType::String => quote! { &self.#field_ident.#link_id  },
                        FieldConvertType::None => quote! { &self.#field_ident.#link_id  },
                    }
                } else {
                    // 考虑可能需要写入null的场景，不对Option进行unwrap
                    quote! { &self.#field_ident }
                };
                let update_set_sql = format!("{}.{} = ?",table_name,inner_field.field_db_name);
                let doc = format!("tiny orm自动生成 - 更新{}",inner_field.field_ident);
                let update_code = quote!{
                    #[doc = #doc]
                    pub async fn #fn_name(&self,pool: &TinyOrmDbPool) ->AnyhowResult<()>
                    {
                        let sql = Self::DB_META.build_update_sql(#update_set_sql,Some(Self::DB_META.pk_where_sql));
                        let query = Self::db_query(&sql)
                            .bind(#value_token)
                            #(.bind(#pk_self_fields))*;
                        Self::db_execute(pool, query).await
                        .with_context(|| "#doc")?;
                        Ok(())
                    }
                };
                Some(update_code)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    quote!{
        #(#update_tokens)*
    }
}


/// 生成字段的orm_query_with方法
fn generate_query_info(orm_field_list: &[TinyOrmFieldData],table_name:&str) -> TokenStream2 {    
    let query_tokens = orm_field_list
        .iter()
        .filter_map(|field| {            
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.is_orm_query {
                // 生成该字段的orm_query方法
                let fn_name = format_ident!("orm_query_with_{}",inner_field.field_ident);
                let field_type = &inner_field.field_type;

                let where_sql = format!("{}.{} = ?",table_name,inner_field.field_db_name);
                let doc = format!("tiny orm自动生成 - 根据{}查询记录",inner_field.field_ident);
                let query_code = if let Some(order_by_sql) = &inner_field.order_by_sql{
                    quote!{
                        #[doc = #doc]
                        pub async fn #fn_name(pool: &TinyOrmDbPool,query_value:#field_type) -> AnyhowResult<Vec<Self>>
                        {
                            let sql = Self::DB_META.build_select_sql_with_order(#where_sql,Some(#order_by_sql));
                            let query = Self::db_query(&sql)
                                .bind(query_value);
                            Self::db_fetch_all(pool, query, Self::orm_row_map).await
                                .with_context(|| #doc)
                        }
                    }
                }else{
                    quote!{
                        #[doc = #doc]
                        pub async fn #fn_name(pool: &TinyOrmDbPool,query_value:#field_type) -> AnyhowResult<Vec<Self>>
                        {
                            let sql = Self::DB_META.build_select_sql(#where_sql);
                            let query = Self::db_query(&sql)
                                .bind(query_value);
                            Self::db_fetch_all(pool, query, Self::orm_row_map).await
                                .with_context(|| #doc)
                        }
                    }
                };
                Some(query_code)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    quote!{
        #(#query_tokens)*
    }
}


/// 生成字段的orm_get_with方法
fn generate_get_info(orm_field_list: &[TinyOrmFieldData],table_name:&str) -> TokenStream2 {    
    let query_tokens = orm_field_list
        .iter()
        .filter_map(|field| {            
            let inner_field = match field {
                TinyOrmFieldData::Join(join_field) => &join_field.field,
                TinyOrmFieldData::Pk(pk_field) => pk_field,
                TinyOrmFieldData::Normal(field) => field,
            };
            if inner_field.is_orm_get {
                // 生成该字段的orm_query方法
                let fn_name = format_ident!("orm_get_with_{}",inner_field.field_ident);
                let field_type = &inner_field.field_type;

                let where_sql = format!("{}.{} = ?",table_name,inner_field.field_db_name);
                let doc = format!("tiny orm自动生成 - 根据{}查询记录",inner_field.field_ident);
                let query_code = quote!{
                    #[doc = #doc]
                    pub async fn #fn_name(pool: &TinyOrmDbPool,query_value:#field_type) -> AnyhowResult<Self>
                    {
                        let sql = Self::DB_META.build_select_sql(#where_sql);
                        let query = Self::db_query(&sql)
                            .bind(query_value);
                        Self::db_fetch_one(pool, query, Self::orm_row_map).await
                            .with_context(|| #doc)
                    }
                };
                Some(query_code)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    quote!{
        #(#query_tokens)*
    }
}